package atlantik.ui;

import static atlantik.Log.warn;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

import javax.swing.JOptionPane;
import javax.xml.parsers.ParserConfigurationException;

import atlantik.ai.SimpleAI;
import atlantik.game.AbstractAtlantikListener;
import atlantik.game.Atlantik;
import atlantik.game.AtlantikClient;
import atlantik.game.AtlantikListenerDispatcher;

import gnu.getopt.Getopt;

public class Main extends AbstractAtlantikListener {

	private final AtlantikListenerDispatcher dispatcher = new AtlantikListenerDispatcher();

	private final Atlantik client;

	private String cookie;

	private final GUI gui;

	private final TextUI tui;

	private final PrintWriter out;

	private SimpleAI ai;

	private static String hostname;

	private static int port;

	private static String name;

	private static boolean startAi;
	
	// see public static void main to enter your server information
	
	public static void main(String[] args) throws IOException,
			ParserConfigurationException {
		
		// Example:
		// host name: georgemoody.com
		// port: 1234
		// name: whatever you want
		// Or, put in the IP address of your local server
		// that is running monopd

		hostname = null;
		port = 0;
		name = null;
		startAi = false;

		Getopt g = new Getopt("JAtlantik", args, "ah:n:p:");
		int c;

		// get arguments from command line.
		while ((c = g.getopt()) != -1) {
			switch (c) {
			case 'a':
				startAi = true;
				break;
			case 'h':
				hostname = g.getOptarg();
				break;
			case 'n':
				name = g.getOptarg();
				break;
			case 'p':
				port = Integer.parseInt(g.getOptarg());
				break;
			default:
				// bail out on a bad option.
				System.exit(1);
				break;
			}
		}

		System.out.print("\n************************************\n" +
				"=== Hello! Welcome to JAtlantik! ===" +
				"\n************************************\n\n");

		// if any options are still empty, pop up the gui where they could enter the
		// missing values. For now, call the text based wizard to fill in the options.
		if (hostname == null || port == 0 || name == null) {
			if (Text_Wizard() == false) {
				System.err.println("\nInvalid options.");
				System.exit(1);
			}
		}

		System.out.print("Player name: " + name + "\n" +
		                 "Server: " + hostname + "\n" +
				 "Port: " + port + "\n" +
				 "AI: " + (startAi ? "enabled" : "disabled") + "\n\n");
		
		Main main = new Main(hostname, port, name);
		if (startAi)
			main.startAi();

	}

	public static boolean Text_Wizard()
	{
		InputStreamReader input = new InputStreamReader(System.in);
		BufferedReader userServerInput = new BufferedReader(input);

		try
		{
			// get server name
			if (hostname == null) {
				System.out.print("Enter the IP address (or URL) of the computer hosting your monopd server\n" +
					"(as a series of numbers separated by periods): ");
				hostname = userServerInput.readLine();
			}
			
			// get port number
			if (port == 0) {
				System.out.print("\nEnter a port number (e.g. 1234): ");
				port = Integer.parseInt(userServerInput.readLine());
			}
			
			// get user name
			if (name == null) {
				System.out.print("\nEnter your name: ");
				name = userServerInput.readLine();	
			}
			
			System.out.print("\n");
			
		} catch (Exception e) // Generic Exception catch "just in case", returns false
		{
			// we had a problem getting the options.
			return false;
		}

		// all options are now filled in.
		return true;
	}

	public Main(String hostname, int port, String name) throws IOException,
			ParserConfigurationException {
		String logfile = hostname + "_" + name + ".log";
		this.out = new PrintWriter(new FileWriter(logfile));
		this.name = name;
		this.client = new AtlantikClient(hostname, port, dispatcher);

		dispatcher.addListener(this);

		gui = new GUI(client);
		gui.setSize(700, 400);
		gui.setVisible(true);

		tui = new TextUI(client, dispatcher, new InputStreamReader(System.in),
				new OutputStreamWriter(System.out));
		tui.start();

		readCookie();

		Runtime.getRuntime().addShutdownHook(new Thread() {
			@Override
			public void run() {
					deleteCookie();
			}
		});
		client.connect();
	}

	public void serverVersion(String version) {
		if (cookie != null)
			client.reconnect(cookie);
		else
			client.setName(name);
	}

	public void clientInfo(int playerId, String cookie) {
		if (this.cookie != null && !this.cookie.equals(cookie))
			client.setName(name);
		this.cookie = cookie;
		writeCookie();
		gui.loggedIn();
		gui.setState(new ConnectedState(client));
	}

	public void xml(String xml) {
		out.println(xml);
		out.flush();
	}

	void writeCookie() {
		PrintWriter out = null;
		try {
			out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(
					name + ".cookie")));
			out.println(cookie);
		} catch (IOException e) {
			warn("Could not write cookie");
		}
		if (out != null)
			out.close();
	}

	void deleteCookie() {
		new File(name + ".cookie").delete();
	}

	public void startAi() {
		if (this.ai != null)
			dispatcher.removeListener(ai);
		ai = new SimpleAI(client, dispatcher);
	}

	void readCookie() {
		BufferedReader in = null;
		try {
			in = new BufferedReader(new InputStreamReader(new FileInputStream(
					name + ".cookie")));
			this.cookie = in.readLine();
		} catch (IOException e) {
			warn("Could not read cookie");
		}
		if (in != null)
			try {
				in.close();
			} catch (IOException e) {
			}
	}
}
